/**
 * @author Tobias Boehm
 *
 * 11.05.2011
 */
package org.anddev.andengine.extension.tbsengine.message.server.preparematch;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.UUID;

import org.anddev.andengine.extension.tbsengine.match.AbsServerMatchPreparation;
import org.anddev.andengine.extension.tbsengine.match.playerslot.AbsPlayerSlot.SlotState;
import org.anddev.andengine.extension.tbsengine.message.server.AbsServerMatchMessage;
import org.anddev.andengine.extension.tbsengine.message.server.DefaultTBSserverMessageFlags;
import org.anddev.andengine.extension.tbsengine.player.BasePlayer;

/**
 * This is an abstract class of a server message which should be used for a
 * reply to a player who wants to join a match preparation.
 * <p>
 * With this message you should provide all necessary information to rebuild the
 * match preparation state on the client side of the application.
 * 
 * @author Tobias Boehm
 *
 * @param <MatchPreparationClass> - Your implementation of {@link AbsServerMatchPreparation}
 */
public abstract class AbsServerMatchpreparationJoinRequestReplyMessage<MatchPreparationClass extends AbsServerMatchPreparation> extends AbsServerMatchMessage implements DefaultTBSserverMessageFlags {

	public static enum JoinRequestAnswerReason{OK,NO_SLOT_AVAILABLE,BANNED_PREVIOUSLY,MATCH_DOES_NOT_EXIST,MATCH_ALREADY_RUNNING,GOODBYE};
	
	
	/*
	 * Common Data
	 */
	protected boolean mAccepted = false;
	protected JoinRequestAnswerReason mConnectionAnswerReason = JoinRequestAnswerReason.NO_SLOT_AVAILABLE;
	
	/*
	 * Server Side Data
	 */
	protected MatchPreparationClass mMatch;
	
	/*
	 * Client Side Data
	 */
	protected UUID mMatchCreatorID;
	protected String mMapID;
	protected HashMap<UUID,BasePlayer> mPlayerIDplayerMap;
	
	protected HashMap<Long,SlotState> mSlotIDslotStateMap;
	protected HashMap<Long,String> mSlotIDfactionNameMap;
	protected HashMap<Long,UUID> mSlotIDplayerIDmap;
	protected HashMap<Long,Integer> mSlotIDteamIDmap;
	
	
	protected abstract void readMatchData(final DataInputStream pDataInputStream, final HashMap<UUID,BasePlayer> pPlayerIDplayer,
										  final HashMap<Long,SlotState> pSlotIDslotState, final HashMap<Long,String> pSlotIDfactionName,
										  final HashMap<Long,UUID> pSlotIDplayerID, final HashMap<Long,Integer> pSlotIDteamID);
	
	protected abstract void writeMatchData(final DataOutputStream pDataOutputStream, final MatchPreparationClass pMatch);
	
	
	/* (non-Javadoc)
	 * @see org.anddev.andengine.extension.multiplayer.protocol.adt.message.IMessage#getFlag()
	 */
	@Override
	public short getFlag() {
		
		return FLAG_SERVER_MATCHPREPARATION_JOIN_REUQEST_REPLY;
	}

	@Override
	protected void onReadTransmissonMatchData(DataInputStream pDataInputStream)
			throws IOException {

		this.mAccepted = pDataInputStream.readBoolean();
		
		this.mConnectionAnswerReason = JoinRequestAnswerReason.valueOf(pDataInputStream.readUTF());
				
		if(this.mAccepted){
					
			this.initMaps();
			
			this.readMatchData(pDataInputStream, this.mPlayerIDplayerMap, this.mSlotIDslotStateMap, this.mSlotIDfactionNameMap, this.mSlotIDplayerIDmap, this.mSlotIDteamIDmap);
		}
	}

	protected void initMaps() {
		
		this.mPlayerIDplayerMap = new HashMap<UUID, BasePlayer>();
		this.mSlotIDslotStateMap = new HashMap<Long, SlotState>();
		this.mSlotIDfactionNameMap = new HashMap<Long, String>();
		this.mSlotIDplayerIDmap = new HashMap<Long, UUID>();
		this.mSlotIDteamIDmap = new HashMap<Long, Integer>();
	}

	@Override
	protected void onWriteTransmissonMatchData(
			DataOutputStream pDataOutputStream) throws IOException {

		pDataOutputStream.writeBoolean(this.mAccepted);
		
		pDataOutputStream.writeUTF(this.mConnectionAnswerReason.name());
		
		if(this.mAccepted){
		
			this.writeMatchData(pDataOutputStream, this.mMatch);
		}
	}

	/**
	 * @return the mConnectionAnswerReason
	 */
	public JoinRequestAnswerReason getJoinRequestAnswerReason() {
		return mConnectionAnswerReason;
	}

	/**
	 * @param mConnectionAnswerReason the mConnectionAnswerReason to set
	 */
	public void setJoinRequestAnswerReason(
			JoinRequestAnswerReason mConnectionAnswerReason) {
		this.mConnectionAnswerReason = mConnectionAnswerReason;
	}

	
	/**
	 * @return the mAccepted
	 */
	public boolean isAccepted() {
		return mAccepted;
	}

	/**
	 * @param mAccepted the mAccepted to set
	 */
	public void setAccepted(boolean mAccepted) {
		this.mAccepted = mAccepted;
	}

	public void setMatchInstance(MatchPreparationClass pMatch) {
		super.setMatchPreparation(pMatch);
		
		this.mMatch = pMatch;
	}

	/**
	 * @return the mMatchCreatorID
	 */
	public UUID getMatchCreatorID() {
		return mMatchCreatorID;
	}
	/**
	 * @return the mMapID
	 */
	public String getMapID() {
		return mMapID;
	}
	/**
	 * @return the mPlayerIDplayer
	 */
	public HashMap<UUID, BasePlayer> getPlayerIDplayer() {
		return mPlayerIDplayerMap;
	}
	/**
	 * @return the mSlotIDslotState
	 */
	public HashMap<Long, SlotState> getSlotIDslotState() {
		return mSlotIDslotStateMap;
	}
	/**
	 * @return the mSlotIDfactionName
	 */
	public HashMap<Long, String> getSlotIDfactionName() {
		return mSlotIDfactionNameMap;
	}
	/**
	 * @return the mSlotIDplayerID
	 */
	public HashMap<Long, UUID> getSlotIDplayerID() {
		return mSlotIDplayerIDmap;
	}
	/**
	 * @return the mSlotIDteamID
	 */
	public HashMap<Long, Integer> getSlotIDteamID() {
		return mSlotIDteamIDmap;
	}
}
